package com.jml.ddd.sample.anemicdomainmodel.service;


import com.jml.ddd.sample.anemicdomainmodel.dao.AccountDao;
import com.jml.ddd.sample.anemicdomainmodel.dao.AccountRecordDao;
import com.jml.ddd.sample.anemicdomainmodel.model.Account;
import com.jml.ddd.sample.anemicdomainmodel.model.AccountRecord;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

import java.time.LocalDateTime;

@Service
public class AccountService {

    private AccountDao accountDao;
    private AccountRecordDao accountRecordDao;
    private TransactionTemplate transactionTemplate;

    public AccountService(AccountDao accountDao, AccountRecordDao accountRecordDao, TransactionTemplate transactionTemplate) {
        this.accountDao = accountDao;
        this.accountRecordDao = accountRecordDao;
        this.transactionTemplate = transactionTemplate;
    }

    /**
     * 增加积分
     */
    public IncreaseResponse increase(IncreaseRequest request) {

        final IncreaseResponseBuilder responseBuilder = new IncreaseResponseBuilder(request, IncreaseResponse.OK);

        //校验入参
        if (request.getAmount() <= 0) {
            return responseBuilder.error(IncreaseResponse.AMOUNT_LESS_THAN_ZERO).build();
        }
        //TODO 校验更多的参数

        Account account = accountDao.findByUserId(request.getUserId());

        //防重校验
        boolean exists = accountRecordDao.exists(account.getId(),
                AccountRecord.TYPE_INCREASE,
                request.getSourceType(),
                request.getSourceId());

        if (exists) {
            return responseBuilder.error(IncreaseResponse.VERSION_CONFLICT).build();
        }

        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                try {
                    //更新余额
                    int result = accountDao.updateBalance(account.getId(),
                            account.getBalance() + request.getAmount(),
                            account.getVersion());

                    //乐观锁冲突
                    if (result == 0) {
                        responseBuilder.error(IncreaseResponse.VERSION_CONFLICT);
                        status.setRollbackOnly();
                        return;
                    }

                    AccountRecord record = new AccountRecord();
                    record.setAccountId(account.getId());
                    record.setType(AccountRecord.TYPE_INCREASE);
                    record.setSourceId(request.getSourceId());
                    record.setSourceType(request.getSourceType());
                    record.setAmount(request.getAmount());
                    record.setCreated(LocalDateTime.now());

                    //插入子记录
                    int r = accountRecordDao.insert(record);
                    System.out.println(r);
                } catch (Exception e) {
                    responseBuilder.error(IncreaseResponse.UNKNOWN).errorMsg(e.getMessage());
                    status.setRollbackOnly();
                }
            }
        });

        return responseBuilder.build();
    }


    public static class IncreaseResponse {
        public static final int OK = 1;
        public static final int AMOUNT_LESS_THAN_ZERO = 2;
        public static final int VERSION_CONFLICT = 3;
        public static final int UNKNOWN = 3;

    }

    public static class IncreaseRequest {
        private int amount;
        private String userId;
        private String sourceId;
        private int sourceType;

        public int getAmount() {
            return amount;
        }

        public void setAmount(int amount) {
            this.amount = amount;
        }

        public String getUserId() {
            return userId;
        }

        public void setUserId(String userId) {
            this.userId = userId;
        }

        public String getSourceId() {
            return sourceId;
        }

        public void setSourceId(String sourceId) {
            this.sourceId = sourceId;
        }

        public int getSourceType() {
            return sourceType;
        }

        public void setSourceType(int sourceType) {
            this.sourceType = sourceType;
        }
    }

    public static class IncreaseResponseBuilder {

        public IncreaseResponseBuilder(IncreaseRequest request, int code) {

        }

        public IncreaseResponseBuilder error(int code) {
            return this;
        }

        public IncreaseResponse build() {
            return null;
        }

        public IncreaseResponseBuilder errorMsg(String message) {
            return this;
        }
    }
}
